﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace TimeBarPlugin.BarModel
{
	internal class BarGenerator : IDisposable
	{
		#region Attributes

		private readonly TimeSpan _barTime;
		private readonly ObservableCollection<BarSourceItem> _source;
		private Bar _currentBar;

		#endregion

		#region Properties

		public ObservableCollection<Bar> Bars { get; private set; }

		#endregion

		#region Public Methods

		public BarGenerator(ObservableCollection<BarSourceItem> source, TimeSpan barTime)
		{
			this.Bars = new ObservableCollection<Bar>();

			_barTime = barTime;

			_source = source;
			_source.CollectionChanged += Source_CollectionChanged; // Disposed
		}

		#endregion

		#region Events

		private void Source_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
		{
			if (e.Action == NotifyCollectionChangedAction.Add)
			{
				BarSourceItem newItem = (BarSourceItem)e.NewItems[0];

				if (_currentBar == null)
				{
					_currentBar = new Bar(newItem.Time);
				}

				if (newItem.IsInMaxMinMode)
				{
					// ReSharper disable PossibleInvalidOperationException
					_currentBar.AddMaxAndMinCandidates(newItem.Time, newItem.MaxValue.Value, newItem.MinValue.Value);
					// ReSharper restore PossibleInvalidOperationException
				}
				else
				{
					// ReSharper disable PossibleInvalidOperationException
					_currentBar.AddValue(newItem.Time, newItem.Value.Value);
					// ReSharper restore PossibleInvalidOperationException
				}

				if (_currentBar.Duration >= _barTime)
				{
					this.Bars.Add(_currentBar);
					_currentBar = null;
				}
			}
		}

		#endregion

				#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				_source.CollectionChanged -= Source_CollectionChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~BarGenerator()
		{
			this.Dispose(false);
		}

		#endregion

	}
}
